import common from '@ohos.app.ability.common';
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import formInfo from '@ohos.app.form.formInfo';
import formProvider from '@ohos.app.form.formProvider';
import preferences from '@ohos.data.preferences';
import Logger from '../common/utils/Logger';

// 用户首选项存储实例对象: 替代 @ohos.data.storage
// 用户首选项为应用提供Key-Value键值型的数据处理能力，支持应用持久化轻量级数据，并对其修改和查询。
// 数据存储形式为键值对，键的类型为字符串型，值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。
let preferences_instance: preferences.Preferences | null = null;

/**
 *获取 Preferences 实例对象
 * @param context Ability 上下文对象
 * @returns Preferences 实例对象
 */
async function getPreferencesInstance(context: common.BaseContext) {
  if (preferences_instance == null) {
    try {
      // 获取Preferences实例，使用callback异步回调
      preferences_instance = await preferences.getPreferences(context, 'MyPreferences');
    } catch (error) {
      Logger.error('getPreferencesInstance', '获取 Preferences 实例对象失败，error:' + JSON.stringify(error));
    }
  }
  return preferences_instance;
}

/**
 * 持久化存储卡片状态
 * @param formId 卡片ID
 * @param stateA 状态A
 * @param stateB 状态B
 */
function storeFormState(context: common.BaseContext, formId: string, stateA: preferences.ValueType, stateB: preferences.ValueType) {
  // 获取Preferences实例，使用callback异步回调
  getPreferencesInstance(context).then(instance => {
    // 持久化卡片的状态： preferences.put(key:string, value:ValueType) -> ValueType = number | string | boolean | Array<number> | Array<string> | Array<boolean>;
    let p1 = instance.put('A' + formId, stateA);
    let p2 = instance.put('B' + formId, stateB);

    Promise.all([p1, p2]).then(() => {
      // 将当前Preferences实例的数据异步存储到用户首选项的持久化文件中
      instance.flush((err => {
        Logger.error('storeFormState', 'preferences.flush failed,error->' + JSON.stringify(err));
      }));
    }).catch(reason => {
      Logger.error('storeFormState', 'preferences.put failed,error->' + JSON.stringify(reason));
    })
  });
}

/**
 * 卡片扩展模块：自定义卡片能力，提供卡片创建、销毁、刷新等生命周期回调
 *
 * 属性：context:FormExtensionContext - ExtensionAbility的上下文环境，继承自ExtensionContext。
 * 配置：在 module.json5 配置文件中的 extensionAbilities 标签下，配置 FormExtensionAbility 相关信息
 *
 * 注意：
 * FormExtensionAbility 进程不能常驻后台，即在卡片生命周期回调函数中无法处理长时间的任务，在生命周期调度完成后会继续存在5秒，如5秒内没有新的生命周期回调触发则进程自动退出。
 * 针对可能需要5秒以上才能完成的业务逻辑，建议拉起主应用进行处理，处理完成后使用 updateForm 通知卡片进行刷新。
 */
export default class EntryFormAbility extends FormExtensionAbility {
  private readonly TAG: string = 'EntryFormAbility';
  count: number = 0;

  /**
   * 使用方创建卡片时触发，提供方需要返回卡片数据绑定类
   * @param want
   * @returns
   */
  onAddForm(want) {
    Logger.info(this.TAG, 'onAddForm, want:' + JSON.stringify(want));
    // Called to return a FormBindingData object.
    // 在使用postCardAction接口的call事件时，需要在FormExtensionAbility中的onAddForm生命周期回调中更新formId
    // 在入参want中可以取出卡片的唯一标识：formId
    let formId: string = want.parameters[formInfo.FormParam.IDENTITY_KEY];
    // 是否是临时卡片
    let isTempCard: boolean = want.parameters[formInfo.FormParam.TEMPORARY_KEY];
    if (isTempCard === false) { // 如果为常态卡片，直接进行信息持久化
      Logger.info(this.TAG, 'Not temp card, init db for:' + formId);
      storeFormState(this.context, formId, false, false);
    }

    let data = {
      formId,
      'title': 'onAddForm 初始化数据',
      'text': '刷新数据',
      'loaded': true,
      'stateA': false,
      'stateB': false
    };
    // 将data封装在formData中并返回至卡片页面
    let formData = formBindingData.createFormBindingData(data);
    return formData;
  }

  /**
   * 使用方将临时卡片转换为常态卡片触发，提供方需要做相应的处理
   * @param formId 卡片的唯一标识
   */
  onCastToNormalForm(formId) {
    // Called when the form provider is notified that a temporary form is successfully
    // converted to a normal form.
    Logger.info(this.TAG, 'onCastToNormalForm, formId:' + formId);
    // 如果在添加时为临时卡片，则建议转为常态卡片时进行信息持久化
    storeFormState(this.context, formId, 'false', 'false');
  }

  /**
   * 更新卡片内容：
   * 触发该生命周期的方式有三种：
   *  1.卡片设置定时更新：配置 form_config.json 中配置 updateEnabled 为 true，设置 updateDuration 值（单位为30分钟，取值为自然数，N 表示每30*N分钟更新一次）
   *  2.卡片设置定点自动更新：：配置 form_config.json 中配置 updateEnabled 为 true，设置 scheduledUpdateTime 值（卡片的定点刷新的时刻，如 "10:30"）
   *  3.使用方（系统应用）主动请求更新：系统应用通过调用 @ohos.app.form.formHost 模块的 formHost.requestForm(formId: string): Promise<void> 方法来触发该生命周期回调
   *    系统应用调用 formHost.requestForm(formId) -> 触发卡片生命周期回调 onUpdateForm(formId) -> 更新卡片内容
   *
   * 注意：
   *  1.若卡片支持上述任何一种情况，则需要重写该方法以支持数据更新
   *  2.定时刷新（updateDuration）和定点刷新（scheduledUpdateTime）两种方式同时配置时，定时刷新优先生效。
   *  3.updateEnabled 为 false：表示不支持周期性刷新。
   *
   * @param formId 卡片的唯一标识
   */
  onUpdateForm(formId) {
    // Called to notify the form provider to update a specified form.
    Logger.info(this.TAG, 'onFormEvent, formId -> ' + formId);
    // 定义卡片UI数据信息
    let formInfo = {
      'title': 'onUpdateForm 更新化数据',
      'text': '卡片生命周期回调 onUpdateForm(formId) -> 更新卡片内容 ' + (new Date()).toISOString(),
      'loaded': true,
    }
    // 将 formInfo 包装成 FormBindingData 类型实例对象
    let formData = formBindingData.createFormBindingData(formInfo)
    // 更新WidgetCard数据
    formProvider.updateForm(formId, formData).then((data) => {
      Logger.info(this.TAG, 'FormAbility updateForm success.' + JSON.stringify(data));
    }).catch((error) => {
      Logger.error(this.TAG, 'FormAbility updateForm failed: ' + JSON.stringify(error));
    })

    // 从持久化存储中获取状态 （如果业务需要）
    // getPreferencesInstance(this.context).then(async (prefer) => {
    //   formInfo['stateA'] = await prefer.get('A' + formId, false);
    //   formInfo['stateB'] = await prefer.get('B' + formId, false);
    //   // formProvider.updateForm ...
    // });
    // // 更新本地持久化状态
    // storeFormState(formId, false, false);
  }

  /**
   * 需要配置 formVisibleNotify 为 true，且为系统应用才会回调
   * @param newStatus
   */
  onChangeFormVisibility(newStatus) {
    // Called when the form provider receives form events from the system.
  }

  /**
   * 接收卡片中 postCardAction({action:'message',...}) message 类型的消息
   *
   * 注意：FormExtensionAbility在触发生命周期回调时被拉起，仅能在后台存在5秒,建议处理数据时间不要超过5秒。
   *
   * 需要在 form_config.json 中配置 formVisibleNotify 为 true，且为系统应用才会回调
   * @param formId 卡片的唯一标识
   * @param message 消息内容 postCardAction 事件的推送的 params 参数
   */
  onFormEvent(formId, message) {
    // Called when a specified message event defined by the form provider is triggered.
    Logger.info(this.TAG, 'onFormEvent, MESSAGE -> ' + message);

    let formInfo = formBindingData.createFormBindingData({
      'title': 'onFormEvent 更新化数据',
      'text': '刷新数据->' + this.count++
    })
    // 更新WidgetCard数据
    formProvider.updateForm(formId, formInfo).then((data) => {
      Logger.info(this.TAG, 'FormAbility updateForm success.' + JSON.stringify(data));
    }).catch((error) => {
      Logger.error(this.TAG, 'FormAbility updateForm failed: ' + JSON.stringify(error));
    })
  }

  /**
   * 当对应的卡片删除时触发的回调，入参是被删除的卡片ID
   * @param formId 卡片的唯一标识
   */
  onRemoveForm(formId) {
    // Called to notify the form provider that a specified form has been destroyed.
    // 在卡片销毁(onRemoveForm)时删除当前卡片存储的持久化信息，避免反复添加删除卡片导致数据库文件持续变大。
    getPreferencesInstance(this.context).then((instance) => {
      // 清除此Preferences实例中的所有存储
      instance.clear((err) => {
        if (err) {
          Logger.error(this.TAG, "Failed to clear Preferences. code =" + err.code + ", message =" + err.message);
          return;
        }
        Logger.info(this.TAG, "Succeeded in clearing Preferences.");
      });
    })
  }

  /**
   * 卡片提供方接收查询卡片状态通知接口，默认返回卡片初始状态
   * @param want
   * @returns
   */
  onAcquireFormState(want) {
    // Called to return a {@link FormState} object.
    return formInfo.FormState.READY;
  }
};